/**
 * @frame.cpp
 * This file is part of FEGRF.
 * 
 * FEGRF is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * See LICENSE file in main folder for more information.
 */

#include <wx/wxprec.h>

#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif

#include "frame.h"
#include "list.h"
#include "resource.h"

#if defined( __WXMSW__ ) && defined( _DEBUG )
#include <wx/msw/msvcrt.h>
#endif

BEGIN_EVENT_TABLE(GRFDialog, wxDialog)
	EVT_BUTTON(DIALOG_BTN_CANCEL, GRFDialog::OnCancel)
	EVT_BUTTON(DIALOG_BTN_EXTRACT, GRFDialog::OnExtract)
	EVT_BUTTON(DIALOG_BTN_INSERT_GRF, GRFDialog::OnInsertGRF)
	EVT_BUTTON(DIALOG_BTN_INSERT_DIR, GRFDialog::OnInsertDIR)
	EVT_BUTTON(DIALOG_BTN_SETTING, GRFDialog::OnSetting)
	EVT_CLOSE(GRFDialog::OnCloseWindow)
END_EVENT_TABLE()

BEGIN_EVENT_TABLE(GRFFrame, wxFrame)
	EVT_TOOL(BTN_SAVE, GRFFrame::OnSave)
	EVT_TOOL(BTN_CLOSE, GRFFrame::OnClose)
	EVT_TOOL(BTN_BACK, GRFFrame::OnBack)
	EVT_TOOL(BTN_NEXT, GRFFrame::OnNext)
	EVT_MENU(MENU_SAVE, GRFFrame::OnSave)
	EVT_MENU(MENU_SAVE_AS, GRFFrame::OnSaveAs)
	EVT_CHAR_HOOK(GRFFrame::OnKeyPressed)
	EVT_SIZE(GRFFrame::OnResize)
END_EVENT_TABLE()

BEGIN_EVENT_TABLE(ImageCanvas, wxScrolledWindow)
	EVT_PAINT(ImageCanvas::OnPaint)
END_EVENT_TABLE()

ImageCanvas::ImageCanvas(wxWindow *parent)
	:wxScrolledWindow(parent, wxID_ANY)
{
	SetScrollRate(1, 1);
	SetDoubleBuffered(true);
}

void ImageCanvas::OnPaint(wxPaintEvent &WXUNUSED(event))
{
	wxPaintDC dc(this);
	PrepareDC(dc);

	wxCoord x = dc.LogicalToDeviceXRel(0);
	wxCoord y = dc.LogicalToDeviceYRel(0);
	if (m_image.GetSize().GetWidth() < 200)
		x = dc.LogicalToDeviceXRel(100 - m_image.GetSize().GetWidth()/2);
	if (m_image.GetSize().GetHeight() < 200)
		y = dc.LogicalToDeviceYRel(100 - m_image.GetSize().GetHeight()/2);
	dc.DrawBitmap(wxBitmap(m_image), x, y, true);

	GRFFrame *parent = (GRFFrame*)GetParent();
	if (parent->m_index > 0)
		dc.DrawText(wxString::Format(_("%d / %d"), parent->m_index, parent->m_spr->get_image_count()), dc.LogicalToDeviceXRel(10), dc.LogicalToDeviceYRel(10));
}

GRFFrame::GRFFrame(wxWindow *parent, wxWindowID id, const wxString &title, const wxPoint &pos, const wxSize &size)
	:wxFrame(parent, id, title, pos, size, (wxFRAME_FLOAT_ON_PARENT | wxFRAME_TOOL_WINDOW | wxDEFAULT_FRAME_STYLE) & ~(wxRESIZE_BORDER | wxMAXIMIZE_BOX))
{
	Centre();

	m_canvas  = NULL;
	m_text	  = NULL;
	m_spr	  = NULL;
	m_index	  = 0;
	m_toolbar = NULL;
	
	SetMinSize(wxSize(200, 200));
	SetBackgroundColour(wxColour(0xFFFFFF));
}

GRFFrame::~GRFFrame()
{
	if (m_spr)
		delete m_spr;
}

void GRFFrame::ShowToolbar(const int flag)
{
	if (flag == 1) {
		//View Image

		m_toolbar = CreateToolBar(wxNO_BORDER | wxTB_FLAT | wxTB_HORIZONTAL | wxTB_NODIVIDER);
		m_toolbar->AddTool(BTN_SAVE, _("Save image as..."), CreateImageFromPngResource("PNG_SAVE").Rescale(24, 24, wxIMAGE_QUALITY_BICUBIC), _("Save image as..."));
		m_toolbar->AddTool(BTN_CLOSE, _("Close"), CreateImageFromPngResource("PNG_CLOSE").Rescale(24, 24, wxIMAGE_QUALITY_BICUBIC), _("Close"));
		m_toolbar->AddSeparator();
		m_toolbar->AddTool(BTN_BACK, _("Back"), CreateImageFromPngResource("PNG_BACK").Rescale(24, 24, wxIMAGE_QUALITY_BICUBIC), _("Back"));
		m_toolbar->AddTool(BTN_NEXT, _("Next"), CreateImageFromPngResource("PNG_NEXT").Rescale(24, 24, wxIMAGE_QUALITY_BICUBIC), _("Next"));
		m_toolbar->Realize();
	} else if (flag == 2) {
		//View Text

		m_toolbar = CreateToolBar(wxNO_BORDER | wxTB_FLAT | wxTB_HORIZONTAL | wxTB_NODIVIDER);
		m_toolbar->AddTool(BTN_SAVE, _("Save"), CreateImageFromPngResource("PNG_SAVE").Rescale(24, 24, wxIMAGE_QUALITY_BICUBIC), _("Save text"), wxITEM_DROPDOWN);

		wxMenu *menu = new wxMenu;
		menu->Append(MENU_SAVE, _("&Save\tCtrl+S"));
		menu->Append(MENU_SAVE_AS, _("Save &As...\tCtrl+Shift+S"));
		m_toolbar->SetDropdownMenu(BTN_SAVE, menu);

		m_toolbar->AddTool(BTN_CLOSE, _("Close"), CreateImageFromPngResource("PNG_CLOSE").Rescale(24, 24, wxIMAGE_QUALITY_BICUBIC), _("Close"));
		m_toolbar->Realize();
	}
}

void GRFFrame::OnSave(wxCommandEvent &WXUNUSED(event))
{
	if (m_canvas) {
		wxString def_path = GetTitle();
		if (def_path.EndsWith(_(".spr"))) {
			def_path.BeforeLast('\\');
			def_path = wxString::Format(_("%s-%d.bmp"), def_path, m_index);
		}
		wxFileDialog file_save_dialog(NULL, _("Save image As"), ((MainFrame*)GetParent())->m_config->Read(_("/History/LastDirectory"), wxEmptyString), def_path, _("All types (*.*)|*.*"), wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
		if (file_save_dialog.ShowModal() != wxID_OK)
			return;
		m_canvas->m_image.SaveFile(file_save_dialog.GetPath());
	} else {
		if (m_text->GetValue() == m_text->GetLabel())
			return;
		MainFrame *parent = (MainFrame*)GetParent();
		wxString file_name = grf_file_get_filename(m_node);
		grf_file_delete(m_node);
		if (m_text->GetValue() != "") //Just delete it if empty..
			grf_file_add(parent->m_grf_handle, file_name.c_str(), (void*)m_text->GetValue().c_str().AsChar(), m_text->GetValue().Len());
		m_text->SetLabel(m_text->GetValue());
		parent->GRFRead();
	}
}

void GRFFrame::OnSaveAs(wxCommandEvent &WXUNUSED(event))
{
	wxString def_path = GetTitle();
	wxFileDialog file_save_dialog(NULL, _("Save image As"), ((MainFrame*)GetParent())->m_config->Read(_("/History/LastDirectory"), wxEmptyString), def_path, _("All types (*.*)|*.*"), wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
	if (file_save_dialog.ShowModal() != wxID_OK)
		return;
	grf_put_contents_to_file(m_node, file_save_dialog.GetPath().c_str());
}

void GRFFrame::OnClose(wxCommandEvent &WXUNUSED(event))
{
	Close();
}

void GRFFrame::OnBack(wxCommandEvent &WXUNUSED(event))
{
	m_index--;
	if (m_index <= 1)
		m_toolbar->EnableTool(BTN_BACK, false);
	m_toolbar->EnableTool(BTN_NEXT, true);
	uint8_t *buff = m_spr->bmp_get_data(m_index-1);
	wxImage image = GetImageFromMemory((char*)buff, m_spr->bmp_get_size(m_index-1), wxBITMAP_TYPE_ANY);
	SetImage(image);
	delete buff;
}

void GRFFrame::OnNext(wxCommandEvent &WXUNUSED(event))
{
	m_index++;
	if (m_index >= m_spr->get_image_count())
		m_toolbar->EnableTool(BTN_NEXT, false);
	m_toolbar->EnableTool(BTN_BACK, true);
	uint8_t *buff = m_spr->bmp_get_data(m_index-1);
	wxImage image = GetImageFromMemory((char*)buff, m_spr->bmp_get_size(m_index-1), wxBITMAP_TYPE_ANY);
	SetImage(image);
	delete buff;
}

void GRFFrame::OnKeyPressed(wxKeyEvent &event)
{
	if (IsActive()) {
		if ((event.GetModifiers() & wxMOD_CONTROL) && event.GetKeyCode() == 'S') {
			if ((event.GetModifiers() & wxMOD_SHIFT) && m_text)
				this->OnSaveAs((wxCommandEvent)NULL);
			else
				this->OnSave((wxCommandEvent)NULL);
		} else
			event.Skip();
	}
}

void GRFFrame::OnResize(wxSizeEvent &WXUNUSED(event))
{
	if (m_text)
		m_text->SetSize(GetClientRect().width, GetClientRect().height);

	Refresh();
}

void GRFFrame::SetText(wxString &text)
{
	if (m_canvas) {
		m_canvas->Destroy();
		m_canvas = NULL;
		m_toolbar->Destroy();
		m_toolbar = NULL;
	}
	if (!m_toolbar) {
		SetWindowStyle(GetWindowStyle() | (wxRESIZE_BORDER | wxMAXIMIZE_BOX));
		ShowToolbar(2);
	}

	if (!m_text)
		m_text = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(GetClientRect().width, GetClientRect().height), wxTE_MULTILINE | wxTE_RICH | wxTE_PROCESS_TAB);

	m_text->SetLabel(text);
}

void GRFFrame::SetSprite(SprFile *spr_file)
{
	if (m_spr)
		delete m_spr;
	m_spr = spr_file;
	m_index = 1;
	uint8_t *buff = m_spr->bmp_get_data(0);
	wxImage image = GetImageFromMemory((char*)buff, m_spr->bmp_get_size(0), wxBITMAP_TYPE_ANY);
	SetImage(image);
	m_toolbar->EnableTool(BTN_BACK, false);
	m_toolbar->EnableTool(BTN_NEXT, false);
	if (m_spr->get_image_count() > 1)
		m_toolbar->EnableTool(BTN_NEXT, true);

	delete buff;
}

void GRFFrame::SetImage(wxImage image)
{
	if (m_text) {
		m_text->Destroy();
		m_text = NULL;
		m_toolbar->Destroy();
		m_toolbar = NULL;
		SetWindowStyle(GetWindowStyle() & ~(wxRESIZE_BORDER | wxMAXIMIZE_BOX));
	}

	if (!m_toolbar) {
		ShowToolbar(1);
		m_toolbar->EnableTool(BTN_BACK, false);
		m_toolbar->EnableTool(BTN_NEXT, false);
	}

	if (!m_canvas)
		m_canvas = new ImageCanvas(this);
	
	wxRect frame_size(wxSize(200, 200));
	m_canvas->m_image = image;
	if (image.GetSize().GetWidth() > frame_size.GetWidth())
		frame_size.width = image.GetSize().GetWidth();
	if (image.GetSize().GetHeight() > frame_size.GetHeight())
		frame_size.height = image.GetSize().GetHeight();
	if (frame_size.height > 480)
		frame_size.height = 480;
	if (frame_size.width > 640)
		frame_size.width = 640;
	SetClientSize(frame_size);
	m_canvas->SetClientSize(frame_size);
	m_canvas->SetVirtualSize(image.GetSize().GetWidth(), image.GetSize().GetHeight());
	Refresh();
}

GRFDialog::GRFDialog(wxWindow *parent, wxWindowID id, const wxString &title, const wxPoint &pos, const wxSize &size)
	:wxDialog(parent, id, title, pos, size, wxDEFAULT_DIALOG_STYLE)
{
	wxPanel *panel = new wxPanel(this, wxID_ANY);
	m_sizer = new wxBoxSizer(wxVERTICAL);
	Centre();

	switch (GetId()) {
		case DIALOG_EXTRACT:
		case DIALOG_EXTRACT_ALL:
		{
			wxStaticBoxSizer *box_checkbox = new wxStaticBoxSizer(wxVERTICAL, panel, _("Options"));
			m_checkbox_dir = new wxCheckBox(panel, CHECK_BOX_DIR, _("Extract with Folder"));
			m_checkbox_ascii = new wxCheckBox(panel, CHECK_BOX_ASCII, _("Convert File name to ASCII"));
			if (((MainFrame*)parent)->m_config->ReadBool(_("/Settings/ExtractWithDirectory"), true))
				m_checkbox_dir->SetValue(true);
			if (((MainFrame*)parent)->m_config->ReadBool(_("/Settings/ExtractConvertToANSI"), true))
				m_checkbox_ascii->SetValue(true);
			box_checkbox->Add(m_checkbox_dir, 0, wxBOTTOM, 5);
			box_checkbox->Add(m_checkbox_ascii);

			wxBoxSizer *sizer_row = new wxBoxSizer(wxHORIZONTAL);
			m_btn_ok = new wxButton(panel, DIALOG_BTN_EXTRACT, _("Extract"));
			m_btn_ok->SetDefault();
			m_btn_cancel = new wxButton(panel, DIALOG_BTN_CANCEL, _("Cancel"));
			sizer_row->Add(m_btn_cancel, 0, wxRIGHT, 10);
			sizer_row->Add(m_btn_ok);

			m_sizer->Add(box_checkbox, 1, wxEXPAND | wxALL, 10);
			m_sizer->Add(sizer_row, 0, wxALIGN_RIGHT | wxRIGHT | wxBOTTOM, 10);
		} break;
		case DIALOG_EXTRACT_ERROR:
		{
			wxStaticText *text_error = new wxStaticText(panel, wxID_ANY, _("Can't extract :"));
			m_listbox = new wxListBox(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, (const wxString*)0, wxLB_SORT | wxLB_HSCROLL);

			wxBoxSizer *sizer_row = new wxBoxSizer(wxHORIZONTAL);
			m_btn_cancel = new wxButton(panel, DIALOG_BTN_CANCEL, _("OK"));
			m_btn_cancel->SetDefault();
			sizer_row->Add(m_btn_cancel);

			m_sizer->Add(text_error, 0, wxTOP | wxLEFT, 10);
			m_sizer->Add(m_listbox, 1, wxEXPAND | wxALL, 10);
			m_sizer->Add(sizer_row, 0, wxALIGN_RIGHT | wxRIGHT | wxBOTTOM, 10);
		} break;
		case DIALOG_INSERT:
		{
			m_load_grf = new wxButton(panel, DIALOG_BTN_INSERT_GRF, _("Insert from GRF"), wxDefaultPosition, wxSize(140, -1));
			m_load_dir = new wxButton(panel, DIALOG_BTN_INSERT_DIR, _("Insert from Directory"), wxDefaultPosition, wxSize(140, -1));
			m_sizer->Add(m_load_grf, 1, wxCENTER | wxALL & ~wxBOTTOM, 10);
			m_sizer->Add(m_load_dir, 1, wxCENTER | wxALL, 10);
		} break;
		case DIALOG_SETTING:
		{
			wxStaticBoxSizer *box_repack = new wxStaticBoxSizer(wxVERTICAL, panel, _("Repack Type"));
			m_radiobtn_fast = new wxRadioButton(panel, GRF_REPACK_FAST, _("Fast"), wxDefaultPosition, wxDefaultSize, wxRB_GROUP);
			m_radiobtn_decrypt = new wxRadioButton(panel, GRF_REPACK_DECRYPT, _("Decrypt"));
			m_radiobtn_recompress = new wxRadioButton(panel, GRF_REPACK_RECOMPRESS, _("Recompress"));
			box_repack->Add(m_radiobtn_fast, 0, wxBOTTOM, 5);
			box_repack->Add(m_radiobtn_decrypt, 0, wxBOTTOM, 5);
			box_repack->Add(m_radiobtn_recompress);

			switch(((MainFrame*)parent)->m_config->ReadLong(_("/Settings/RepackType"), 0)) {
				case GRF_REPACK_DECRYPT:
					m_radiobtn_decrypt->SetValue(true);
					break;
				case GRF_REPACK_RECOMPRESS:
					m_radiobtn_recompress->SetValue(true);
					break;
				default:
					m_radiobtn_fast->SetValue(true);
					break;
			}

			wxStaticBoxSizer *box_encoding = new wxStaticBoxSizer(wxVERTICAL, panel, _("Encoding Type"));
			m_radiobtn_ansi = new wxRadioButton(panel, ENC_ANSI, _("ANSI"), wxDefaultPosition, wxDefaultSize, wxRB_GROUP);
			m_radiobtn_euc_kr = new wxRadioButton(panel, ENC_EUC_KR, _("EUC_KR"));
			m_radiobtn_local = new wxRadioButton(panel, ENC_LOCAL, _("Local"));
			box_encoding->Add(m_radiobtn_ansi, 0, wxBOTTOM, 5);
			box_encoding->Add(m_radiobtn_euc_kr, 0, wxBOTTOM, 5);
			box_encoding->Add(m_radiobtn_local);

			switch(((MainFrame*)parent)->m_config->ReadLong(_("/Settings/Encoding"), 0)) {
				case ENC_ANSI:
					m_radiobtn_ansi->SetValue(true);
					break;
				case ENC_EUC_KR:
					m_radiobtn_euc_kr->SetValue(true);
					break;
				default:
					m_radiobtn_local->SetValue(true);
					break;
			}

			wxBoxSizer *sizer_row1 = new wxBoxSizer(wxHORIZONTAL);
			sizer_row1->Add(box_repack, 1, wxEXPAND | wxALL, 10);
			sizer_row1->Add(box_encoding, 1, wxEXPAND | wxALL, 10);

			wxStaticBoxSizer *box_compress_level = new wxStaticBoxSizer(wxVERTICAL, panel, _("Compression Level"));
			m_slider_complevel = new wxSlider(panel, wxID_ANY, ((MainFrame*)parent)->m_config->ReadLong(_("/Settings/CompressionLevel"), 5), 1, 9, wxDefaultPosition, wxDefaultSize, wxSL_LABELS | wxSL_TICKS);
			box_compress_level->Add(m_slider_complevel, 1, wxEXPAND | wxLEFT | wxRIGHT, 10);

			wxBoxSizer *sizer_row2 = new wxBoxSizer(wxHORIZONTAL);
			m_btn_ok = new wxButton(panel, DIALOG_BTN_SETTING, _("OK"));
			m_btn_ok->SetDefault();
			m_btn_cancel = new wxButton(panel, DIALOG_BTN_CANCEL, _("Cancel"));
			sizer_row2->Add(m_btn_cancel, 0, wxRIGHT, 10);
			sizer_row2->Add(m_btn_ok);

			m_sizer->Add(sizer_row1, 1, wxEXPAND | wxTOP, 10);
			m_sizer->Add(box_compress_level, 1, wxEXPAND | wxALL, 10);
			m_sizer->Add(sizer_row2, 0, wxALIGN_RIGHT | wxRIGHT | wxBOTTOM, 10);
		} break;
		default:
			break;
	}
	panel->SetSizer(m_sizer);
}

void GRFDialog::OnCancel(wxCommandEvent &event)
{
	EndModal(-1);
}

void GRFDialog::OnExtract(wxCommandEvent &event)
{
	int flag = 0;
	if (m_checkbox_dir->IsChecked())
		flag |= EXTRACT_WITH_DIRECTORY;
	if (m_checkbox_ascii->IsChecked())
		flag |= EXTRACT_CONVERT_ASCII;
	EndModal(flag);
}

void GRFDialog::OnInsertGRF(wxCommandEvent &event)
{
	EndModal(INSERT_GRF);
}

void GRFDialog::OnInsertDIR(wxCommandEvent &event)
{
	EndModal(INSERT_DIR);
}

void GRFDialog::OnSetting(wxCommandEvent &event)
{
	MainFrame *parent = (MainFrame*)GetParent();
	int flag;

	flag = ENC_LOCAL;
	if (m_radiobtn_ansi->GetValue())
		flag = ENC_ANSI;
	else if (m_radiobtn_euc_kr->GetValue())
		flag = ENC_EUC_KR;
	parent->m_config->Write(_("/Settings/Encoding"), flag);
	parent->m_grf_list->SetEncoding(flag);

	flag = GRF_REPACK_FAST;
	if (m_radiobtn_decrypt->GetValue())
		flag = GRF_REPACK_DECRYPT;
	else if (m_radiobtn_recompress->GetValue())
		flag = GRF_REPACK_RECOMPRESS;
	parent->m_config->Write(_("/Settings/RepackType"), flag);

	parent->m_config->Write(_("/Settings/CompressionLevel"), m_slider_complevel->GetValue());

	parent->SettingsSave();
	EndModal(-1);
}

void GRFDialog::OnCloseWindow(wxCloseEvent &event)
{
	event.Veto();
	EndModal(-1);
}

void GRFDialog::AddList(wxArrayString string)
{
	m_listbox->Append(string);
}
